#include "confparser.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>

static FILE *_myinetdconf;

void confparser_open() {
  _myinetdconf = fopen(CONF_FILE, "r");
  if(_myinetdconf == NULL) {
    snprintf(err_message, MAX_ERR_MSG, "Failed to open configuration 'file' = 'myinetd.conf'.\n");
    log_message(LOG_FILE, err_message);
    exit(1);
  }
}

Service *confparser_getService() {
  static int line_counter = 1;
  Service *service = (Service *) malloc(sizeof(Service));
  char *aux, *endptr;

  while((aux = fgets(service->line, MAX_LINE_SIZE, _myinetdconf)) != NULL &&
	service->line[0] == '#');

  if(aux == NULL) {
    free(service);
    return NULL;
  }  

  if(service->line[strlen(service->line)-1] == '\n') {
    service->line[strlen(service->line)-1] = '\0';
  } else {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Line is longer than MAX_LINE_SIZE = '%d'.\n", line_counter, MAX_LINE_SIZE);
    log_message(LOG_FILE, err_message);
    exit(1);
  }

  service->name = strtok(service->line, " ");
  if(service->name == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'name'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);      
  }

  aux = strtok(NULL, " ");
  if(aux == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'port'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);
  }
  service->port = (unsigned int) strtoul(aux, &endptr, 0); 
  if (*endptr != '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Invalid parameter 'port' = '%s'.\n", line_counter, aux);
    log_message(LOG_FILE, err_message);
    exit(1);
  } else if (service->port > 65535 || service->port < 0) {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Parameter 'port' = '%u' outside of valid range [0->65535].\n", line_counter, service->port);
    log_message(LOG_FILE, err_message);
    exit(1);
  }

  aux = strtok(NULL, " ");
  if(aux == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'type'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);
  } else if(!strcmp(aux, "stream")) {
    service->type = SOCK_STREAM;
  } else if(!strcmp(aux, "dgram")) {
    service->type = SOCK_DGRAM;
  } else {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Unknown socket 'type' = '%s'.\n", line_counter, aux);
    log_message(LOG_FILE, err_message);
    exit(1);
  }
  
  aux = strtok(NULL, " ");
  if(aux == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'protocol'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);
  } else if(!strcmp(aux, "tcp")) {
    if(service->type != SOCK_STREAM) {
      snprintf(err_message, MAX_ERR_MSG, "Line %d: Socket 'type' and 'protocol' are incompatible.\n", line_counter, aux);
      log_message(LOG_FILE, err_message);
      exit(1);
    }
    service->protocol = 0;
  } else if(!strcmp(aux, "udp")) {
    if(service->type != SOCK_DGRAM) {
      snprintf(err_message, MAX_ERR_MSG, "Line %d: Socket 'type' and 'protocol' are incompatible.\n", line_counter, aux);
      log_message(LOG_FILE, err_message);
      exit(1);
    }
    service->protocol = 0;
  } else {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Unknown socket 'type' = '%s'.\n", line_counter, aux);
    log_message(LOG_FILE, err_message);
    exit(1);
  }

  aux = strtok(NULL, " ");
  if(aux == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'wait/nowait'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);
  } else if(!strcmp(aux, "wait")) {
    if(service->type != SOCK_DGRAM) {
      snprintf(err_message, MAX_ERR_MSG, "Line %d: Socket 'type' and 'wait/nowait' are incompatible.\n", line_counter, aux);
      log_message(LOG_FILE, err_message);
      exit(1);
    }
    service->wait = 1;
  } else if(!strcmp(aux, "nowait")) {
    if(service->type != SOCK_STREAM) {
      snprintf(err_message, MAX_ERR_MSG, "Line %d: Socket 'type' and 'wait/nowait' are incompatible.\n", line_counter, aux);
      log_message(LOG_FILE, err_message);
      exit(1);
    }
    service->wait = 0;
  } else {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Unknown socket 'wait/nowait' = '%s'.\n", line_counter, aux);
    log_message(LOG_FILE, err_message);
    exit(1);
  }

  service->pathname = strtok(NULL, " ");
  if(service->pathname == '\0') {
    snprintf(err_message, MAX_ERR_MSG, "Line %d: Missing parameter 'pathname'.\n", line_counter);
    log_message(LOG_FILE, err_message);
    exit(1);      
  }

  service->argc = 0;
  while((aux = strtok(NULL, " ")) != NULL ) {
    if(service->argc == MAX_ARGS_SIZE) {
      snprintf(err_message, MAX_ERR_MSG, "Line %d: Number of arguments is bigger than 'MAX_ARGS_SIZE' = %d.\n", line_counter, MAX_ARGS_SIZE);
      log_message(LOG_FILE, err_message);
      exit(1);
    }
    service->args[service->argc]=aux;
    service->argc++;
  }

  line_counter++;
  
  return service;
}

void confparser_destroyService(Service *service) {
  free(service);
}

void confparser_close() {
  fclose(_myinetdconf);
}
